package com.mingqijia.gassafety.job.job.statistic;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.mingqijia.gassafety.db.entity.CmStatDevicealarm;
import com.mingqijia.gassafety.db.entity.auth.DictionaryItemEntry;
import com.mingqijia.gassafety.db.entity.vo.DeviceAlarmStatTotalVo;
import com.mingqijia.gassafety.db.entity.vo.DeviceAlarmStatVo;
import com.mingqijia.gassafety.db.mapper.CmStatDevicealarmMapper;
import com.mingqijia.gassafety.db.mapper.DtuMapper;
import com.mingqijia.gassafety.db.mapper.auth.DictionaryItemMapper;
import com.mingqijia.gassafety.job.feign.ConsoleSkFeignClient;
import com.mingqijia.gassafety.job.request.ConsoleSkSupplierListRequest;
import com.mingqijia.gassafety.job.response.AlarmSupplierListVo;
import com.mingqijia.gassafety.job.response.ConsoleSkSupplierListResponse;
import com.mingqijia.gassafety.job.service.cmp.EquipmentCmpService;
import com.mingqijia.gassafety.shared.constant.Constants;
import com.mingqijia.gassafety.shared.constant.EquipmentType;
import com.mingqijia.gassafety.shared.utils.RedisCacheExt;
import com.xxl.job.core.biz.model.ReturnT;
import com.xxl.job.core.handler.annotation.XxlJob;
import com.xxl.job.core.log.XxlJobLogger;

import org.apache.commons.collections.CollectionUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

import cn.hutool.core.date.DateUtil;
import lombok.extern.slf4j.Slf4j;

/**
 * 设备告警统计处理
 * @Author: duanhongxiang
 * @Date: 2024/5/30 19:58
 */
@Configuration
@EnableScheduling
@Slf4j
public class DeviceAlarmStatJob {

    @Autowired
    RedisCacheExt redisUtil;

    @Autowired
    DictionaryItemMapper dictionaryItemMapper;

    @Autowired
    CmStatDevicealarmMapper cmStatDevicealarmMapper;

    @Autowired
    private EquipmentCmpService equipmentCmpService;

    @Autowired
    DtuMapper dtuMapper;

    @XxlJob("dpDeviceAlarmStat")
    //@Scheduled(cron = "* 0/1 * * * ?")
    public ReturnT<String> dpDeviceAlarmStat(String param) {
        XxlJobLogger.log("XXLJOB-dpDeviceAlarmStat start...");
        log.info("dpDeviceAlarmStat--start--------,param:{}",param);
        String key = Constants.CM_STAT_DEVICE;
        try {
            Boolean acquire = redisUtil.setIfAbsent(key, String.valueOf(System.currentTimeMillis()), Constants.TIME_OUT);//15分钟超时
            if (acquire) {
                try {
                    log.info("dpDeviceAlarmStat--进入执行器--------");
                    if (execute(param)) {
                        return ReturnT.SUCCESS;
                    } else {
                        return ReturnT.FAIL;
                    }
                } catch (Exception e) {
                    log.info("dpDeviceAlarmStat-error:{}", e);
                } finally {
                    redisUtil.del(key);
                }
            }
        } catch (Exception e) {
            log.info("dpDeviceAlarmStat-error:{}", e);
        }

        log.info("dpDeviceAlarmStat--end--------");
        XxlJobLogger.log("XXLJOB-dpDeviceAlarmStat end...");
        return ReturnT.SUCCESS;
    }

    private boolean execute(String param) {
        String statDate;
        if( isValidDate(param) ){
            statDate = param;
        }else{
            LocalDate yesterday = LocalDate.now().minusDays(1);
            statDate = yesterday.format(DateTimeFormatter.ofPattern("yyyy-MM-dd"));
        }
        String beginDate = statDate + " 00:00:00";
        String endDate = statDate + " 23:59:59";

        log.info("开始统计开始时间beginDate:{}至endDate:{}的设备告警数据",beginDate,endDate);

        List<DeviceAlarmStatVo> list;
        LambdaQueryWrapper<CmStatDevicealarm> queryCountWrapper = new LambdaQueryWrapper<>();
        queryCountWrapper.eq(CmStatDevicealarm::getUpdateSource, "1");
        if( "all".equals(param) ){
            if( cmStatDevicealarmMapper.selectCount(queryCountWrapper) >0 ){
                log.info("请清除数据之后再重新刷所有数据");
                XxlJobLogger.log("请清除数据之后再重新刷所有数据");
                return false;
            }
            list =  dtuMapper.selectDeviceAlarmStatListByDate(null,endDate);
        }else{
            queryCountWrapper.eq(CmStatDevicealarm::getDataDate, statDate);
            if( cmStatDevicealarmMapper.selectCount(queryCountWrapper) >0 ){
                log.info("请清除指定日期{}数据之后再重新刷所有数据",statDate);
                XxlJobLogger.log("请清除指定日期"+statDate+"数据之后再重新刷该日期数据");
                return false;
            }
            list =  dtuMapper.selectDeviceAlarmStatListByDate(beginDate,endDate);
        }

        // 查询远程接口，不查字典
        ConsoleSkSupplierListResponse response = equipmentCmpService.supplierListRequest();
        Map<String,String> manufacturerMap = new HashMap<>();
        if (null != response && null != response.getData() && CollectionUtils.isNotEmpty(response.getData()) ) {
            log.info("结束调用厨房查询厂商接口，返回数据长度：{}", response.getData().size());
            manufacturerMap = response.getData().stream()
                    .collect(Collectors.toMap(
                            AlarmSupplierListVo::getAlarmSystemCode,
                            AlarmSupplierListVo::getMsName,
                            (k1, k2) -> k2
                    ));
        }

        if (!ObjectUtils.isEmpty(list)) {
            Date currDate = new Date();
            List<CmStatDevicealarm> cmStatDevicealarms = new ArrayList<>();
            for (DeviceAlarmStatVo deviceAlarmStatVo: list){
                CmStatDevicealarm cmStatDevicealarm = new CmStatDevicealarm();
                BeanUtils.copyProperties(deviceAlarmStatVo,cmStatDevicealarm);

                Integer totalAlarm = 0;
                Integer totalDevice = 0;
                Integer totalAlarmWork = 0;
                Integer totalAlarmProcessing = 0;
                String stateDate = DateUtil.format(deviceAlarmStatVo.getDataDate(),"yyyy-MM-dd");
                List<DeviceAlarmStatTotalVo> totalVos = dtuMapper.selectDeviceAlarmStatTotalByDate(stateDate+" 23:59:59",
                        deviceAlarmStatVo.getSpId(),deviceAlarmStatVo.getEsCode(),deviceAlarmStatVo.getDeviceType());
                if( !ObjectUtils.isEmpty(totalVos) ){
                    for (DeviceAlarmStatTotalVo deviceAlarmStatTotalVo:totalVos){
                        if( null!=deviceAlarmStatTotalVo.getTotalAlarm() ){
                            totalAlarm += deviceAlarmStatTotalVo.getTotalAlarm();
                        }
                        if( null!=deviceAlarmStatTotalVo.getTotalDevice() ){
                            totalDevice += deviceAlarmStatTotalVo.getTotalDevice();
                        }
                        if( null!=deviceAlarmStatTotalVo.getTotalAlarmWork() ){
                            totalAlarmWork += deviceAlarmStatTotalVo.getTotalAlarmWork();
                        }
                        if( null!=deviceAlarmStatTotalVo.getTotalAlarmProcessing() ){
                            totalAlarmProcessing += deviceAlarmStatTotalVo.getTotalAlarmProcessing();
                        }
                    }
                }
                cmStatDevicealarm.setTotalAlarm(totalAlarm);
                cmStatDevicealarm.setTotalDevice(totalDevice);
                cmStatDevicealarm.setTotalAlarmProcessing(totalAlarmProcessing);
                cmStatDevicealarm.setTotalAlarmWork(totalAlarmWork);

                cmStatDevicealarm.setEsName("");
                if( manufacturerMap.containsKey(deviceAlarmStatVo.getEsCode()) ){
                    cmStatDevicealarm.setEsName(manufacturerMap.get(deviceAlarmStatVo.getEsCode()));
                }

                cmStatDevicealarm.setTypeName(EquipmentType.parse(deviceAlarmStatVo.getDeviceType()).getName());

                if( EquipmentType.HOME_GAS_DETECTOR.getCode().equalsIgnoreCase(deviceAlarmStatVo.getDeviceType()) ){
                    cmStatDevicealarm.setMyType("1");
                }else{
                    cmStatDevicealarm.setMyType("2");
                }

                cmStatDevicealarm.setUpdateSource("1");
                cmStatDevicealarm.setCreateTime(currDate);

                String uuid = UUID.randomUUID().toString();
                cmStatDevicealarm.setId(StringUtils.replace(uuid,"-",""));

                cmStatDevicealarms.add(cmStatDevicealarm);

                if( cmStatDevicealarms.size()>=2 ){
                    cmStatDevicealarmMapper.insertBatch(cmStatDevicealarms);
                    cmStatDevicealarms.clear();
                    cmStatDevicealarms = new ArrayList<>();
                }
            }
            if( cmStatDevicealarms.size()>0 ){
                cmStatDevicealarmMapper.insertBatch(cmStatDevicealarms);
            }
        }
        log.info("新增数据处理完成");
        if( !"all".equals(param) ){
            handleUpdatedAtData(beginDate,endDate,manufacturerMap);
            log.info("变更数据处理完成");
        }
        return true;
    }


    private void handleUpdatedAtData(String beginDate,String endDate,Map<String,String> manufacturerMap){
        List<DeviceAlarmStatVo> lists = dtuMapper.selectDeviceAlarmStatListByUpdatedAt(beginDate,endDate);

        log.info("变更数据数量:{}",lists.size());

        for (DeviceAlarmStatVo deviceAlarmStatVo : lists) {
            String stateDate = DateUtil.format(deviceAlarmStatVo.getDataDate(),"yyyy-MM-dd");
            Integer totalAlarm = 0;
            Integer totalDevice = 0;
            Integer totalAlarmWork = 0;
            Integer totalAlarmProcessing = 0;
            List<DeviceAlarmStatTotalVo> totalVos = dtuMapper.selectDeviceAlarmStatTotalByUpdatedAt(stateDate+" 23:59:59",
                    deviceAlarmStatVo.getSpId(),deviceAlarmStatVo.getEsCode(),deviceAlarmStatVo.getDeviceType());
            if( !ObjectUtils.isEmpty(totalVos) ){
                for (DeviceAlarmStatTotalVo deviceAlarmStatTotalVo:totalVos){
                    if( null!=deviceAlarmStatTotalVo.getTotalAlarm() ){
                        totalAlarm += deviceAlarmStatTotalVo.getTotalAlarm();
                    }
                    if( null!=deviceAlarmStatTotalVo.getTotalDevice() ){
                        totalDevice += deviceAlarmStatTotalVo.getTotalDevice();
                    }
                    if( null!=deviceAlarmStatTotalVo.getTotalAlarmWork() ){
                        totalAlarmWork += deviceAlarmStatTotalVo.getTotalAlarmWork();
                    }
                    if( null!=deviceAlarmStatTotalVo.getTotalAlarmProcessing() ){
                        totalAlarmProcessing += deviceAlarmStatTotalVo.getTotalAlarmProcessing();
                    }
                }
            }

            List<CmStatDevicealarm> lastDatas = cmStatDevicealarmMapper.selectLastStatDeviceAlarmStatus(
                    deviceAlarmStatVo.getSpId(),
                    deviceAlarmStatVo.getEsCode(),
                    deviceAlarmStatVo.getDeviceType()
            );

            Date currDate = new Date();

            CmStatDevicealarm cmStatDevicealarm = new CmStatDevicealarm();
            LambdaQueryWrapper<CmStatDevicealarm> updateWrapper = new LambdaQueryWrapper<>();
            updateWrapper.eq(CmStatDevicealarm::getSpId, deviceAlarmStatVo.getSpId());
            updateWrapper.eq(CmStatDevicealarm::getDataDate, deviceAlarmStatVo.getDataDate());
            updateWrapper.eq(CmStatDevicealarm::getEsCode, deviceAlarmStatVo.getEsCode());
            updateWrapper.eq(CmStatDevicealarm::getDeviceType, deviceAlarmStatVo.getDeviceType());
            updateWrapper.eq(CmStatDevicealarm::getUpdateSource, "1");
            if( null!=lastDatas && lastDatas.size()>0 ){//存在记录
                int compareTo1 = lastDatas.get(0).getTotalAlarmProcessing().compareTo(totalAlarmProcessing);
                int compareTo2 = lastDatas.get(0).getTotalAlarmWork().compareTo(totalAlarmWork);
                if( lastDatas.get(0).getDataDate().getTime() == deviceAlarmStatVo.getDataDate().getTime() &&
                        (compareTo1 ==0 && compareTo2==0) ){//当天有记录,且上一条数据总数大于当天数据
                    if( lastDatas.size()==2 ){
                        cmStatDevicealarm.setNewAlarmWork(totalAlarmWork - lastDatas.get(1).getTotalAlarmWork());
                        cmStatDevicealarm.setNewAlarmProcessing(totalAlarmProcessing - lastDatas.get(1).getTotalAlarmProcessing());
                        cmStatDevicealarmMapper.update(cmStatDevicealarm,updateWrapper);
                    }
                }else if( lastDatas.get(0).getDataDate().getTime() == deviceAlarmStatVo.getDataDate().getTime() &&
                        (compareTo1<0 || compareTo2<0) ){//当天有记录,且上一条数据总数小于当天数据
                    if (compareTo1 < 0) {
                        cmStatDevicealarm.setNewAlarmProcessing(deviceAlarmStatVo.getNewAlarmProcessing() - lastDatas.get(0).getNewAlarmProcessing());
                        cmStatDevicealarm.setTotalAlarmProcessing(totalAlarmProcessing);
                    }
                    if (compareTo2 < 0) {
                        cmStatDevicealarm.setNewAlarmWork(deviceAlarmStatVo.getNewAlarmWork() - lastDatas.get(0).getNewAlarmWork());
                        cmStatDevicealarm.setTotalAlarmWork(totalAlarmWork);
                    }
                    cmStatDevicealarm.setUpdateTime(currDate);
                    cmStatDevicealarmMapper.update(cmStatDevicealarm,updateWrapper);
                }else if( lastDatas.get(0).getDataDate().getTime() < deviceAlarmStatVo.getDataDate().getTime() && (compareTo1 != 0 || compareTo2!=0)){//当天没有记录
                    int newAlarmWork = 0;
                    int newAlarmProcessing = 0;
                    if (compareTo1 < 0) {
                        newAlarmProcessing = totalAlarmProcessing - lastDatas.get(0).getTotalAlarmProcessing();
                    }
                    if (compareTo2 < 0) {
                        newAlarmWork = totalAlarmWork - lastDatas.get(0).getTotalAlarmWork();
                    }
                    BeanUtils.copyProperties(deviceAlarmStatVo,cmStatDevicealarm);
                    cmStatDevicealarm.setTotalDevice(totalDevice);
                    cmStatDevicealarm.setTotalAlarm(totalAlarm);
                    cmStatDevicealarm.setNewAlarmWork(newAlarmWork);
                    cmStatDevicealarm.setNewAlarmProcessing(newAlarmProcessing);
                    cmStatDevicealarm.setTotalAlarmWork(totalAlarmWork);
                    cmStatDevicealarm.setTotalAlarmProcessing(totalAlarmProcessing);
                    createNewDeviceAlarmStat(cmStatDevicealarm,manufacturerMap);
                }
            }else {//不存在记录，新增记录
                BeanUtils.copyProperties(deviceAlarmStatVo,cmStatDevicealarm);
                cmStatDevicealarm.setTotalDevice(totalDevice);
                cmStatDevicealarm.setTotalAlarm(totalAlarm);
                cmStatDevicealarm.setNewAlarmWork(totalAlarmWork);
                cmStatDevicealarm.setTotalAlarmWork(totalAlarmWork);
                cmStatDevicealarm.setNewAlarmProcessing(totalAlarmProcessing);
                cmStatDevicealarm.setTotalAlarmProcessing(totalAlarmProcessing);
                createNewDeviceAlarmStat(cmStatDevicealarm,manufacturerMap);
            }
        }
    }

    private void createNewDeviceAlarmStat(CmStatDevicealarm cmStatDevicealarm,
                                          Map<String,String> manufacturerMap){
        cmStatDevicealarm.setNewDevice(0);
        cmStatDevicealarm.setNewAlarm(0);
        cmStatDevicealarm.setEsName("");
        if( manufacturerMap.containsKey(cmStatDevicealarm.getEsCode()) ){
            cmStatDevicealarm.setEsName(manufacturerMap.get(cmStatDevicealarm.getEsCode()));
        }

        cmStatDevicealarm.setTypeName(EquipmentType.parse(cmStatDevicealarm.getDeviceType()).getName());

        if( EquipmentType.HOME_GAS_DETECTOR.getCode().equalsIgnoreCase(cmStatDevicealarm.getDeviceType()) ){
            cmStatDevicealarm.setMyType("1");
        }else{
            cmStatDevicealarm.setMyType("2");
        }

        cmStatDevicealarm.setUpdateSource("1");
        cmStatDevicealarm.setCreateTime(new Date());
        cmStatDevicealarm.setUpdateTime(new Date());

        String uuid = UUID.randomUUID().toString();
        cmStatDevicealarm.setId(StringUtils.replace(uuid,"-",""));

        cmStatDevicealarmMapper.insert(cmStatDevicealarm);
    }

    private boolean isValidDate(String date) {
        String regex = "^\\d{4}-\\d{2}-\\d{2}$";
        Pattern pattern = Pattern.compile(regex);
        Matcher matcher = pattern.matcher(date);
        return matcher.matches();
    }
}
